home *** CD-ROM | disk | FTP | other *** search
- ━───────────────────────────────────
- X680x0アセンブラ講座 ~番外編~
-
- 《命令のクロック数を計るプログラム》
-
- 鎌田 誠
- ────────────────────────────────────
-
- Motorola のマニュアルに書いてある命令のクロック数を検証するには、自分
-
- でプログラムを書いて実際に所要時間を調べるのが一番確実です。その具体例を
-
- 紹介します。
-
-
- ━───────────────────────────────────
-
- _optime
-
- ────────────────────────────────────
-
- ● _optime とは
-
- サブルーチン _optime は、指定されたサブルーチンを呼び出して帰ってくる
-
- までの時間を計るプログラムです。タイマーを 2 本使って 1μs(0.000001 秒)
-
- 単位で最大 12799μs(0.012799 秒)まで計ることができます。これを越えると
-
- 正しい結果が得られません。
-
- 10MHz の 1 クロックは 0.1μs なので、命令 1 個の時間を直接計ることはで
-
- きません。12799μs 以内でなるべく多く繰り返して、全体の所要時間を繰り返
-
- した回数で割ることで 1 回あたりの所要時間を求めます。なお、結果には命令
-
- を繰り返すために使用される分岐命令の所要時間も含まれます。また、呼び出し
-
- に必要な jsr/rts の所要時間も含まれるので、なるべく多く繰り返した方が正
-
- 確な値が求まります。
-
-
- ● _optime の呼び出し方
-
- _optime は Timer-C と Timer-D を使います。これらのタイマーを標準以外の
-
- 目的で使用している場合は正常に動作しません。
-
- _optime は必ずスーパーバイザモードで呼び出さなければなりません。
-
- _optime の呼び出し方は次のようになっています。
-
- ┌────────────────────────────────
- │ move.l #count,-(sp) ;初期化ルーチンのパラメータ(ループ回数など)
- │ pea.l op_tini ;後始末ルーチン(不要ならば0)
- │ pea.l op_init ;初期化ルーチン(不要ならば0)
- │ pea.l op_main ;計測するルーチン
- │ jsr optime
- │ lea.l (16,sp),sp
-
- 次のような前宣言をすることで C のプログラムから呼び出すこともできます。
-
- ┌────────────────────────────────
- │int optime(void op_main(void), void op_init(int count), void op_tini(void), int count);
-
-
- ● _optime の動作
-
- _optime は、op_init(初期化ルーチン)、op_main(計測するルーチン)、
-
- op_tini(後始末ルーチン)の順序で 2 回呼び出し、2 回目の op_main の所要
-
- 時間だけ計測します。2 回呼び出すのは、計測ルーチンをキャッシュに乗せるた
-
- めです。一連の呼び出し(6 回のサブルーチンコール)は割り込みを禁止した状
-
- 態で行われます。
-
-
- ●レジスタの扱いについて
-
- op_init では op_main で使用するレジスタの準備をして下さい。optime の 4
-
- 番目の引数(count)が op_init に渡されるので、これをレジスタに設定するな
-
- どします。メモリを確保するといった大掛かりな処理も可能ですが、割り込みが
-
- 禁止されているのでディスクのアクセスなどはできません。op_init で設定され
-
- たレジスタは d0-d7/a0-a5 の内容がそのまま op_main に渡されます。
-
- op_main では d0-d7/a0-a6 をすべて使えます。ただし、_optime が op_main
-
- を呼び出すときに jsr (a6) として a6 レジスタを使用しているので、a6 レジ
-
- スタは op_init から引き継ぐことができません。
-
- op_tini は後始末です。通常は不要でしょう。op_init でメモリを確保したと
-
- きは必ずここで開放して下さい。
-
-
- ◎ optime.s を見る TYPE=DOC:optime.s
-
-
- ━───────────────────────────────────
-
- メインルーチン
-
- ────────────────────────────────────
-
- _optime はサブルーチンなので、これを実行するにはメインルーチンが必要で
-
- す。
-
- 計測対象のルーチンを _op_init、_op_main、_op_tini という名前で呼び出す
-
- メインルーチンを用意しました。コマンドラインでループ回数(op_init の引数)
-
- を指定することができます。このソースだけ C で書いてあります。
-
-
- ◎ main.c を見る TYPE=DOC:main.c
-
-
- ━───────────────────────────────────
-
- 具体例(その1)
-
- ────────────────────────────────────
-
- NOP+SUBQ.L #xx,Dn+Bcc.S の所要クロック数を調べます。
-
- NOP は 68000 では 4 クロック、68030 では 2 クロック、68060 では 9 クロ
-
- ックの命令です。
-
- SUBQ.L #xx,Dn は 68000 では 8 クロック、68030 では 2 クロック、68060
-
- では 1 クロックの命令です。
-
- Bcc.S は 68000 では 10 クロック、68030 では 6 クロック、68060 では 0
-
- クロック(分岐予測あり)です。
-
-
- ●ソース
-
- ┌────────────────────────────────
- 1│;nop+subq.l+bcc.s
- 2│ .text
- 3│ .even
- 4│_op_init::
- 5│ move.l (4,sp),d0
- 6│ rts
- 7│
- 8│ .even
- 9│_op_tini::
- 10│ rts
- 11│
- 12│ .align 16
- 13│_op_main::
- 14│ ; 000 030 060
- 15│@@: nop ; 4 0-2-0 9
- 16│ subq.l #1,d0 ; 8 2-0-0 1
- 17│ bne.s @b ; 10 6-0-0 0
- 18│ ; =22 =10 =10
- 19│ rts
- 20│
- 21│_op_name::
- 22│ .dc.b 'nop',0
-
-
- ●結果
-
- ・X68000XVI 10MHz での結果
- [nop] total=11313(μs) count=5000 each=2.2626(μs) each=22.626(clock/10MHz)
-
- ・X68000XVI 16MHz での結果
- [nop] total=10694(μs) count=8000 each=1.3368(μs) each=22.2796(clock/16.667MHz)
-
- ・X68000XVI 24MHz(REDZONE)での結果
- [nop] total=9191(μs) count=10000 each=0.9191(μs) each=22.0584(clock/24MHz)
-
- ・X68030 での結果
- [nop] total=8000(μs) count=20000 each=0.4(μs) each=10(clock/25MHz)
-
- ・X68030+060turbo での結果
- [nop] total=10000(μs) count=50000 each=0.2(μs) each=10(clock/50MHz)
-
-
- ●補足
-
- 68060 のクロック数が多いのは、NOP 命令がパイプラインを掃除するための命
-
- 令だからです。コードにパッチを当てるときに隙間を埋めるためには
-
- MOVEA.L A0,A0 を使います。
-
-
- ━───────────────────────────────────
-
- 具体例(その2)
-
- ────────────────────────────────────
-
- MULU.W Dn,Dn+SUBQ.L #xx,Dn+Bcc.S の所要クロック数を調べます。
-
- MULU.W Dn,Dn は 68000 では 38~70 クロック、68030 では 28 クロック、
-
- 68060 では 2 クロックの命令です。これを確認します。68000 のクロック数は
-
- ソースオペランドに含まれる 1 のビットの数に比例しますが、ここではワース
-
- トケースの $FFFF で計っています。
-
- MULU.W Dn,Dn 1 回の所要時間が X68000XVI 10MHz で 7μs、060turbo で
-
- 0.04μs ですから、ワーストケースで所要時間が 175 倍も違うことがわかりま
-
- す。
-
-
- ●ソース
-
- ┌────────────────────────────────
- 1│;mulu+subq.l+bcc.s
- 2│ .text
- 3│ .even
- 4│_op_init::
- 5│ move.l (4,sp),d0
- 6│ move.w #$FFFF,d1 ;worst case
- 7│ rts
- 8│
- 9│ .even
- 10│_op_tini::
- 11│ rts
- 12│
- 13│ .align 16
- 14│_op_main::
- 15│ ; 000 030 060
- 16│@@: move.w d1,d2 ; 4 2-0-0 1
- 17│ mulu.w d2,d2 ; 70 2-26-0 2
- 18│ subq.l #1,d0 ; 8 2-0-0 1
- 19│ bne.s @b ; 10 6-0-0 0
- 20│ ; =92 =38 =4
- 21│ rts
- 22│
- 23│_op_name::
- 24│ .dc.b 'mulu',0
-
-
- ●結果
-
- ・X68000XVI 10MHz での結果
- [mulu] total=9245(μs) count=1000 each=9.245(μs) each=92.45(clock/10MHz)
-
- ・X68000XVI 16MHz での結果
- [mulu] total=11063(μs) count=2000 each=5.5315(μs) each=92.1935(clock/16.667MHz)
-
- ・X68000XVI 24MHz(REDZONE)での結果
- [mulu] total=11529(μs) count=3000 each=3.843(μs) each=92.232(clock/24MHz)
-
- ・X68030 での結果
- [mulu] total=12161(μs) count=8000 each=1.5201(μs) each=38.0031(clock/25MHz)
-
- ・X68030+060turbo での結果
- [mulu] total=12000(μs) count=150000 each=0.08(μs) each=4(clock/50MHz)
-
-
- (EOF)
-